﻿using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using MassIntellect.WorkIt;
using MassIntellect.WorkIt.Frames;

namespace AIS2.Frames
{
	// ReSharper disable UnusedMember.Global
	public class AISReportLoader : ServiceDependedFrame<IDAService>
	// ReSharper restore UnusedMember.Global
	{
		[Serialize]
		public string ContentKey { get; set; }

		[Serialize]
		public string SenderKey { get; set; }

		[Serialize]
		public string SubjectKey { get; set; }

		[Serialize]
		public string ReportIDKey { get; set; }

		[Serialize]
		public string MessageIDKey { get; set; }

		[Serialize]
		public string TrainIDKey { get; set; }

		[Serialize]
		public string ErrorsKey { get; set; }

		[Serialize]
		public string CodeOPKey { get; set; }
#if DEBUG
		private readonly XmlSchemaSet XsdSet;
#endif
		public AISReportLoader()
		{
#if DEBUG
			XsdSet = new XmlSchemaSet();
			foreach (var item in Directory.GetFiles(@"Schemas\"))
				using (var fs = new FileStream(item, FileMode.Open, FileAccess.Read))
					XsdSet.Add(XmlSchema.Read(fs, null));
#endif
		}

		protected override void protectedPulse(PulseArgs args)
		{
			if (GetService() != null)
			{
				Guid? trainID;
				XElement errors;
				Guid MessageID;
				LoadPack(
					args[GetKeyOrDefault(ContentKey, "Content")] as XElement,
					(Guid?)args[GetKeyOrDefault(SubjectKey, "Subject")],
					(Guid?)args[GetKeyOrDefault(ReportIDKey, "ReportID")],
					args[GetKeyOrDefault(CodeOPKey, "CodeOP")].GoString(),
					out trainID, out errors, out MessageID, args.Id
					);
				args[GetKeyOrDefault(TrainIDKey, "TrainID")] = trainID;
				args[GetKeyOrDefault(ErrorsKey, "Errors")] = errors;
				args[GetKeyOrDefault(MessageIDKey, "MessageID")] = MessageID;
				ThroughPulse(args);
			}
		}

		private void CheckDatabase()
		{
			using (var db = Service.GetContext())
			{
				if (!db.DatabaseExists())
#if DEBUG
				{
					db.CreateDatabase();
				}
#else
					throw new Exception("База данных не найдена");
#endif
			}
		}

		public void LoadPack(XElement aisRep, Guid? ppvID, Guid? reportID, string codeOP, out Guid? trainID, out XElement loadRep, out Guid messageID, Guid pulseID)
		{
			trainID = messageID = Guid.Empty;			
			loadRep = new XElement("AisReportResult",
								   new XElement("MessageID", ppvID),
								   new XElement("PPVID", ppvID),
								   new XElement("CodeOP", codeOP));
			if (aisRep != null)
			{
				CheckDatabase();

				#region Подготовка загрузчика

				var loader = ServiceLocator.Resolve<IAISReportLoadSession>(true);
				//var loader = = new AISReportLoadSession(Service, aisRep, ppvID.Value, reportID, codeOP, Log, ThrowException); 
					
				loader.Service = Service;
				loader.Source = aisRep;
				loader.PPVID = ppvID.Value;
				loader.ReportID = reportID;
				loader.CodeOP = codeOP;
				loader.LogHandler = Log;
				loader.ExceptionHandler = ThrowException;
				#endregion



				// Загрузка отчёта
				loader.Load();
				messageID = loader.ReportSummary != null
					? (loader.ReportSummary.ErrorMessageID ?? Guid.NewGuid())
					: Guid.NewGuid();
				trainID = loader.PiRwInformationInfo.Train.ID;

				loadRep.Add(new XElement("Result", loader.ErrorManager.HasCriticalErrors || loader.IsTDCountCollision ? "ERROR" :
					loader.ErrorManager.HasWarnings ? "WARNING" : "OK"));

				loadRep.Add(loader.ErrorManager
									.Where(s => s.Level > ErrorLevel.Corrected)
									.GroupBy(s => s.ObjectRef)
									.Select(s => new XElement("ResultText",
															  new XElement("GoodsShipmentID", s.Key),
															  new XElement("Text", s
																					.OrderByDescending(s1 => s1.Level)
																					.Select(s1 => s1.Description)
																					.Aggregate((total, next) => total + Environment.NewLine + next)))));

				loadRep.Add(new XElement("ReportStatusTD",
							new XElement("ReportTD", loader.TDinReport),
							new XElement("AcceptTD", loader.TDLoaded)));

				loadRep.Add(new XElement("ReportStatusGS",
							new XElement("ReportGS", loader.GSinReport),
							new XElement("AcceptGS", loader.GSLoaded)));

				//if (!loader.ErrorManager.HasCriticalErrors)
				//{
				//    loadRep.Add(new XElement("ReportStatusTD", "Отчётность загружена успешно. Получено {0} ТД.".goFormat(loader.TDLoaded)));
				//}
			}
			else
			{
				Log("В сообщении {0} не найден PI_RwInformation.", reportID);
				loadRep.Add(new XElement("Result", "ERROR"),
					new XElement("ResultText", "Внутренняя ошибка сервера ЦО. В потоке не найдено сообщение PI_RwInformation."));
			}
#if DEBUG
			new XDocument(loadRep).Validate(XsdSet, null);
#endif
		}
	}
}